<?php

declare(strict_types=1);

namespace App\Chat\Service\Message;

use App\Chat\Cache\GroupCache;
use App\Chat\Cache\SocketRoom;
use App\Chat\Cache\UnreadTalkCache;
use App\Chat\Constant\TalkEventConstant;
use App\Chat\Constant\TalkModeConstant;
use App\Chat\Service\SocketClientService;
use App\Chat\Ws\Contact\ISender;
use App\CustHub\Mapper\ChCustomerServiceMapper;
use App\CustHub\Mapper\ChRoomMapper;
use App\CustHub\Model\ChRoom;
use App\CustHub\Model\ChTalkRecord;
use App\CustHub\Model\ChTalkSession;

class SubscribeHandleService
{
    /**
     * 消息事件与回调事件绑定
     *
     * @var array
     */
    const EVENTS = [
        // 聊天消息事件
        TalkEventConstant::EVENT_TALK          => 'onConsumeTalk',

        // 键盘输入事件
        TalkEventConstant::EVENT_TALK_KEYBOARD => 'onConsumeKeyboard',

        // 用户在线状态事件
        TalkEventConstant::EVENT_LOGIN         => 'onConsumeOnlineStatus',

        // 聊天消息推送事件
        TalkEventConstant::EVENT_TALK_REVOKE   => 'onConsumeRevokeTalk',

        // 好友申请相关事件
        TalkEventConstant::EVENT_CONTACT_APPLY => 'onConsumeFriendApply',

        // 聊天未读消息清除推送事件
        TalkEventConstant::EVENT_TALK_UNREAD_CLEAR   => 'onConsumeUnreadClear',

        //客户删除用户发送消息失败，需要验证
        TalkEventConstant::EVENT_TALK_NEED_VERIFY => 'onConsumeNeedVerify',
    ];

    private SocketClientService $clientService;

    public function __construct(SocketClientService $clientService)
    {
        $this->clientService = $clientService;
    }

    /**
     * @param array $data 数据 ['uuid' => '','event' => '','data' => '','options' => ''];
     */
    public function handle(array $data)
    {
        if (!isset($data['uuid'], $data['event'], $data['data'], $data['options'])) {
            return;
        }
        if (isset(self::EVENTS[$data['event']])) {
            call_user_func([$this, self::EVENTS[$data['event']]], $data);
        }
    }

    /**
     * 对话聊天消息
     *
     * @param array $data 队列消息
     */
    public function onConsumeTalk(array $data): void
    {
        $talk_type   = $data['data']['talk_type'];
        $sender_id   = $data['data']['sender_id'];
        $receiver_id = $data['data']['receiver_id'];
        $record_id   = $data['data']['record_id'];
        $user_id     = $data['data']['user_id'];
        $form_room_id = $data['data']['form_room_id'];
        $quote_content = $data['data']['quote_content'] ?? [];
        $roomData = $data['data']['room_data'] ?? null;

        stdout_log()->info("发送消息测试".json_encode($roomData));

        if($user_id == 0){
            return;
        }

        $groupInfo = null;
         if ($talk_type == TalkModeConstant::GROUP_CHAT) {
            $customerService = container()->get(ChCustomerServiceMapper::class)->findById($user_id);
            if(empty($customerService)){
                return;
            }
            $groupInfo = container()->get(ChRoomMapper::class)->findByRoomWxid($form_room_id, $customerService->main_uid);
        }

        // 客户端ID去重
        $result = $this->getRecordInfo($record_id);
        if (!$result) return;

        $message = di()->get(FormatMessageService::class)->handleChatRecords([$result->toArray()])[0];

        container()->get(ISender::class)->send($user_id,$this->toJson(TalkEventConstant::EVENT_TALK, [
            'sender_id'   => $sender_id,
            'receiver_id' => $receiver_id,
            'form_room_id' => $form_room_id,
            'talk_type'   => $talk_type,
            'data'        => array_merge($message, [
                'group_name'   => $groupInfo ? $groupInfo['group_name'] : '',
                'group_avatar' => $groupInfo ? $groupInfo['avatar'] : '',
                'quote_content' => $quote_content
            ]),
            'room_data' => $roomData
        ]));
    }

    private function getRecordInfo($record_id)
    {
        $result = ChTalkRecord::query()
            ->leftJoin('ch_robot', function ($join) {
                $join->on('ch_talk_records.robot_id', '=', 'ch_robot.id')
                    ->where('ch_talk_records.is_cs', 1);
            })
            ->leftJoin('ch_contact', function ($join) {
                $join->on('ch_talk_records.sender', '=', 'ch_contact.user_id')
                    ->where('ch_talk_records.is_cs', 0)
                    ->where('ch_talk_records.user_id', '>', 0);
            })
            ->select([
                'ch_talk_records.*',
                \Hyperf\DbConnection\Db::raw('IF(ch_talk_records.is_cs = 1, ch_robot.avatar, ch_contact.avatar) as avatar'),
                \Hyperf\DbConnection\Db::raw('IF(ch_talk_records.is_cs = 1, ch_robot.nickname, ch_contact.nickname) as nickname')
            ])
            ->where('ch_talk_records.id', $record_id)
            ->first([
                'ch_talk_records.id',
                'ch_talk_records.talk_type',
                'ch_talk_records.msg_type',
                'ch_talk_records.robot_id',
                'ch_talk_records.user_id',
                'ch_talk_records.content',
                'ch_talk_records.is_revoke',
                'ch_talk_records.created_at',
                \Hyperf\DbConnection\Db::raw('IF(ch_talk_records.is_cs = 1, ch_robot.avatar, ch_contact.avatar) as avatar'),
                \Hyperf\DbConnection\Db::raw('IF(ch_talk_records.is_cs = 1, ch_robot.nickname, ch_contact.nickname) as nickname')
            ]);
        return $result;
    }

    /**
     * 用户上线或下线消息
     *
     * @param array $data 队列消息
     */
    public function onConsumeOnlineStatus(array $data): void
    {
        // todo 2025 05 29 与企微好友聊天 默认都在线 不做任何处理
        $user_id = (int)$data['data']['user_id'];
        $status  = (int)$data['data']['status'];

//        $ids = di()->get(ContactRepository::class)->findAllFriendIds($user_id);
        $ids = [];
        if (empty($ids)) return;

        $fds = [];
        foreach ($ids as $friend_id) {
            $fds[] = $this->clientService->findUserFds(intval($friend_id));
        }

        $fds = array_unique(array_merge(...$fds));

        $this->push($fds, $this->toJson(TalkEventConstant::EVENT_LOGIN, [
            'user_id' => $user_id,
            'status'  => $status
        ]));
    }


    /**
     * 撤销聊天消息
     *
     * @param array $data 队列消息
     */
    public function onConsumeRevokeTalk(array $data): void
    {
        $record = $this->getRecordInfo($data['data']['record_id']);
        $fds = [];
        $groupInfo = [];
        if ($record->talk_type == TalkModeConstant::PRIVATE_CHAT) {
            $fds[] = $this->clientService->findUserFds($record->user_id);
        } else if ($record->talk_type == TalkModeConstant::GROUP_CHAT) {
            $fds[] = $this->clientService->findUserFds($record->user_id);
            $customerService = container()->get(ChCustomerServiceMapper::class)->findById($record->user_id);
            $groupInfo = container()->get(ChRoomMapper::class)->findByRoomWxid($record->from_room_id, $customerService->main_uid);
        }
        if (empty($fds)) return;

        $fds = array_unique(array_merge(...$fds));

        if (!$fds) return;

        $message = di()->get(FormatMessageService::class)->handleChatRecords([$record->toArray()])[0];

        container()->get(ISender::class)->send($record->user_id,$this->toJson(TalkEventConstant::EVENT_TALK_REVOKE, [
            'talk_type'   => $record->talk_type,
            'from_room_id' => $record->from_room_id,
            'sender_id'   => $record->sender,
            'receiver_id' => $record->receiver,
            'record_id'   => $record->id,
            'data'        => array_merge($message, [
                'group_name'   => $groupInfo ? $groupInfo['group_name'] : '',
                'group_avatar' => $groupInfo ? $groupInfo['avatar'] : ''
            ])
        ]));
    }

    public function onConsumeNeedVerify(array $data)
    {
        $record = $this->getRecordInfo($data['data']['record_id']);
        $groupInfo = [];
        if($record->talk_type == TalkModeConstant::GROUP_CHAT) {
            $customerService = container()->get(ChCustomerServiceMapper::class)->findById($record->user_id);
            $groupInfo = container()->get(ChRoomMapper::class)->findByRoomWxid($record->from_room_id, $customerService->main_uid);
        }

        $message = di()->get(FormatMessageService::class)->handleChatRecords([$record->toArray()])[0];
        container()->get(ISender::class)->send($record->user_id,$this->toJson(TalkEventConstant::EVENT_TALK_NEED_VERIFY, [
            'talk_type'   => $record->talk_type,
            'from_room_id' => $record->from_room_id,
            'sender_id'   => $record->sender,
            'receiver_id' => $record->receiver,
            'record_id'   => $record->id,
            'data'        => array_merge($message, [
                'group_name'   => $groupInfo ? $groupInfo['group_name'] : '',
                'group_avatar' => $groupInfo ? $groupInfo['avatar'] : ''
            ])
        ]));
    }

    public function onConsumeUnreadClear(array $data): void
    {
        $sessionInfo = ChTalkSession::query()
            ->where('id',$data['data']['session_id'])
            ->first();
        if($sessionInfo){
            UnreadTalkCache::getInstance()->reset($sessionInfo->user_id,$sessionInfo->robot_id,$sessionInfo->talk_type, $sessionInfo->receiver_id);
        }
        container()->get(ISender::class)->send($sessionInfo->user_id,$this->toJson(TalkEventConstant::EVENT_TALK_UNREAD_CLEAR, [
            'msg'   => '操作成功'
        ]));
    }

    private function toJson(string $event, array $data): string
    {
        return json_encode(["event" => $event, "content" => $data]);
    }

    /**
     * WebSocket 消息推送
     *
     * @param array  $fds
     * @param string $message
     */
    private function push(array $fds, string $message): void
    {
        $server = server();
        foreach ($fds as $fd) {
            $exist = $server->exist(intval($fd));
            if (!$exist) {
                stdout_log()->warning("ws-推送消息失败，fd不存在：" . $fd);
                continue;
            }
            $rst = $server->push(intval($fd), $message);
            stdout_log()->warning("ws-推送消息结果：" . $fd.'==='.$rst ? '成功':'失败');
        }
    }
}